use crate::net::Socket;

/// 系统内核重叠结构
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct Overlapped
{
    pub internal: usize,
    pub internal_high: usize,
    pub anonymous: u64,
    pub h_event: isize,
}

/// 系统内核数据缓冲区结构
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct WsaBuf
{
    pub len: u32,
    pub buf: *mut u8,
}

/// 创建完成端口
#[inline(always)]
pub fn create_io_completion_port() -> isize
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::CreateIoCompletionPort(windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE, 0, 0, 0) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 绑定到完成端口
#[inline(always)]
pub fn create_io_completion_port2<KeyT>(socket: Socket, iocp: isize, completion_key: *mut KeyT) -> isize
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::CreateIoCompletionPort(socket as isize, iocp, completion_key as usize, 0) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 尝试从指定的 I/O 完成端口取消 I/O 完成数据包的排队。 如果没有排队的完成数据包，该函数将等待与完成端口关联的挂起 I/O 操作完成。
/// 若要一次性取消对多个 I/O 完成数据包进行排队，请使用 GetQueuedCompletionStatusEx 函数。
///
/// [in] iocp：
/// 完成端口的句柄。 若要创建完成端口，请使用 CreateIoCompletionPort 函数。
///
/// [out] byte_count：
/// 指向接收在已完成 I/O 操作中传输的字节数的变量的指针。
///
/// [out] completion_key：
/// 指向接收与 I/O 操作已完成的文件句柄关联的完成键值的变量的指针。 完成键是在 对 CreateIoCompletionPort 的调用中指定的每文件密钥。
///
/// [out] overlapped：
/// 指向一个变量的指针，该变量接收在启动完成的 I/O 操作时指定的 OVERLAPPED 结构的地址。
/// 即使已将函数传递给与完成端口和有效的 OVERLAPPED 结构关联的文件句柄，应用程序也可以阻止完成端口通知。 为此，请为 OVERLAPPED 结构的 hEvent 成员指定有效的事件句柄，并设置其低序位。 设置低顺序位的有效事件句柄使 I/O 完成无法排队到完成端口。
///
/// [in] timeout：
/// 调用方愿意等待完成数据包出现在完成端口上的毫秒数。 如果完成数据包未出现在指定时间内，函数超时，返回 FALSE，并将 *lpOverlapped 设置为 NULL。
/// 如果 timeout 为 INFINITE，则函数永远不会超时。如果 timeout 为零，并且没有要取消排队的 I/O 操作，则函数将立即超时。
#[inline(always)]
pub fn get_queued_completion_status<KeyT, OverlappedT>(iocp: isize, byte_count: *mut u32, completion_key: *mut *mut KeyT, overlapped: *mut *mut OverlappedT, timeout: u32) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe {
        windows_sys::Win32::System::IO::GetQueuedCompletionStatus(
            iocp,
            byte_count,
            completion_key as *mut usize,
            overlapped as *mut *mut windows_sys::Win32::System::IO::OVERLAPPED,
            timeout,
        )
    }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 投递数据到完成端口
///
/// iocp：要向其发布 I/O 完成数据包的 I/O 完成端口的句柄。
///
/// byte_count：要通过 GetQueuedCompletionStatus 函数的 byte_count 参数返回的值。
///
/// completion_key：要通过 GetQueuedCompletionStatus 函数的 completion_key 参数返回的值。
///
/// lpoverlapped：要通过 GetQueuedCompletionStatus 函数的 lpoverlapped 参数返回的值。
#[inline(always)]
pub fn post_queued_completion_status<KeyT, OverlappedT>(iocp: isize, byte_count: u32, completion_key: *mut KeyT, overlapped: *const OverlappedT) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::PostQueuedCompletionStatus(iocp, byte_count, completion_key as usize, overlapped as *const windows_sys::Win32::System::IO::OVERLAPPED) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 取消由指定文件的调用线程颁发的所有挂起输入和输出 (I/O) 操作。 该函数不会取消其他线程针对文件句柄发出的 I/O 操作。
/// 若要从另一个线程取消 I/O 操作，请使用 CancelIoEx 函数。
#[inline(always)]
pub fn cancel_io(socket: Socket) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::CancelIo(socket as isize) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 标记指定文件句柄的任何未完成 I/O 操作。 该函数仅取消当前进程中的 I/O 操作，而不管哪个线程创建了 I/O 操作。
///
/// [in] hFile：文件的句柄。
///
/// [in] lpOverlapped：指向包含用于异步 I/O 的数据的 重叠 数据结构的指针。
/// 如果此参数为 NULL，则会取消 hFile 参数的所有 I/O 请求。
/// 如果此参数不是 NULL，则只有为具有指定 lpOverlapped 重叠结构的文件颁发的特定 I/O 请求被标记为已取消，这意味着可以取消一个或多个请求，而 CancelIo 函数会取消文件句柄上的所有未完成请求。
#[inline(always)]
pub fn cancel_io_ex<OverlappedT>(socket: Socket, overlapped: *const OverlappedT) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::CancelIoEx(socket as isize, overlapped as *const windows_sys::Win32::System::IO::OVERLAPPED) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 将指定的线程颁发的挂起的同步 I/O 操作标记为已取消。
#[inline(always)]
pub fn cancel_synchronous_io(thread: isize) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe { windows_sys::Win32::System::IO::CancelSynchronousIo(thread) }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 投递异步接受网络连接。
///
/// slisten_socket：标识已使用 侦听 函数调用的套接字的描述符。 服务器应用程序等待尝试在此套接字上连接。
///
/// saccept_socket：标识要接受传入连接的套接字的描述符。 此套接字不得绑定或连接。
///
/// output_buffer：指向一个缓冲区的指针，用于接收在新连接上发送的第一个数据块、服务器的本地地址和客户端的远程地址。 接收数据从偏移量零开始写入缓冲区的第一部分，而地址将写入缓冲区的后一部分。
///
/// buffer_length：缓冲区大小，最小不能小于64，如果等于64则接受连接不会导致接收操作。 相反，在连接到达时 ，AcceptEx 会立即完成，而无需等待任何数据。
///
/// lpoverlapped：用于处理请求的 OVERLAPPED 结构。
#[inline(always)]
pub fn accept_ex<OverlappedT>(slisten_socket: Socket, saccept_socket: Socket, output_buffer: *mut u8, buffer_length: u32, overlapped: *mut OverlappedT) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe {
        let mut byte_count: u32 = 0;
        windows_sys::Win32::Networking::WinSock::AcceptEx(
            slisten_socket,
            saccept_socket,
            output_buffer as *mut core::ffi::c_void,
            buffer_length - ((std::mem::size_of::<windows_sys::Win32::Networking::WinSock::SOCKADDR_IN>() as u32 + 16) * 2),
            std::mem::size_of::<windows_sys::Win32::Networking::WinSock::SOCKADDR_IN>() as u32 + 16,
            std::mem::size_of::<windows_sys::Win32::Networking::WinSock::SOCKADDR_IN>() as u32 + 16,
            &mut byte_count as *mut u32,
            overlapped as *mut windows_sys::Win32::System::IO::OVERLAPPED,
        )
    }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 投递异步发送网络数据
#[inline(always)]
pub fn wsa_send<OverlappedT>(socket: Socket, buffers: *const WsaBuf, overlapped: *mut OverlappedT) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe {
        //屏蔽掉立即完成情况
        let mut count: u32 = 0;
        windows_sys::Win32::Networking::WinSock::WSASend(
            socket,
            buffers as *const windows_sys::Win32::Networking::WinSock::WSABUF,
            1,
            &mut count as *mut u32,
            0,
            overlapped as *mut windows_sys::Win32::System::IO::OVERLAPPED,
            None,
        )
    }
    #[cfg(not(target_os = "windows"))]
    -1
}

/// 投递异步接收网络数据
#[inline(always)]
pub fn wsa_recv<OverlappedT>(socket: Socket, buffers: *const WsaBuf, overlapped: *mut OverlappedT) -> i32
{
    #[cfg(target_os = "windows")]
    unsafe {
        //屏蔽掉立即完成情况
        let mut count: u32 = 0;
        let mut flag: u32 = 0;
        windows_sys::Win32::Networking::WinSock::WSARecv(
            socket,
            buffers as *const windows_sys::Win32::Networking::WinSock::WSABUF,
            1,
            &mut count as *mut u32,
            &mut flag as *mut u32,
            overlapped as *mut windows_sys::Win32::System::IO::OVERLAPPED,
            None,
        )
    }
    #[cfg(not(target_os = "windows"))]
    -1
}
